package com.kylin.common.saas.datasource;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.HikariDataSourceCreator;
import com.baomidou.dynamic.datasource.ds.ItemDataSource;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.kylin.common.saas.configuration.SaaSProperties;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 数据源管理
 * @author wuhao
 * @version 1.0 - 2022/7/20
 */
@Component
@Slf4j
public class DataSourceManager {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private HikariDataSourceCreator dataSourceCreator;

    @Autowired
    private SaaSProperties saaSProperties;

    // 同步锁
    private final Lock lock = new ReentrantLock();

    /**
     * 从动态数据源中获取数据源
     * @param  dataSourceId 数据源ID
     * @return
     */
    public DataSource getDbSource(String dataSourceId) {
        synchronized (lock) {
            // todo 注意清空不需要的连接，用户自定义的数据库连接 5分钟清除
            // 如果动态数据源不存在，则尝试从数据源重载
            // 通过数据源名称获取数据源
            DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) dataSource;
            DataSource dynamicDataSource = dynamicRoutingDataSource.getDataSources().get(dataSourceId);
//            DataSource dynamicDataSource = dynamicRoutingDataSource.getDataSource(dataSourceId);

            String dataSourceUrl = "";
//            if (dynamicDataSource != null && !dynamicDataSource.equals(dynamicRoutingDataSource.determineDataSource())) {
            if (dynamicDataSource != null) {
                HikariDataSource hikariDataSource = (HikariDataSource) ((ItemDataSource) dynamicDataSource).getDataSource();
                log.info("当前数据源连接地址：" + hikariDataSource.getJdbcUrl());
                return dynamicDataSource;
            }

            String dbName = saaSProperties.getDataSource().getDbName();
            String jdbcUrl = saaSProperties.getDataSource().getUrl();
            // 拼接上租户ID
            if (StringUtils.isNotEmpty(jdbcUrl)) {
                jdbcUrl = jdbcUrl.replace(dbName, dbName + "_" + dataSourceId);
            }
            String userName = saaSProperties.getDataSource().getUsername();
            String password = saaSProperties.getDataSource().getPassword();
//        com.kylin.gen.entity.DataSource dbDataSource = dataSourceMapper.selectById(dataSourceId);
            // 检查是否可连接()
            Boolean result = checkDataSource(jdbcUrl, userName, password);
            if (result) {
                DataSourceProperty dataSourceProperty = new DataSourceProperty();
                // 把数据资源库表ID当数据源名称
                dataSourceProperty.setPoolName(dataSourceId);
                dataSourceProperty.setUrl(jdbcUrl);
                dataSourceProperty.setUsername(userName);
                dataSourceProperty.setPassword(password);
                dataSourceProperty.setDriverClassName(convertDbDriverClassName("mysql"));
                DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
                dynamicRoutingDataSource.addDataSource(dataSourceId, dataSource);
                dynamicDataSource = dynamicRoutingDataSource.getDataSource(dataSourceId);
            }
//            if (dynamicDataSource != null && !dynamicDataSource.equals(dynamicRoutingDataSource.determineDataSource())) {
                return dynamicDataSource;
//            }
//            return null;
        }
    }


    /**
     * 检验连接是否正常
     * @param jdbcUrl jdbc url
     * @param dbUser 用户名
     * @param dbPassword 密码
     * @return
     */
    private Boolean checkDataSource(String jdbcUrl, String dbUser, String dbPassword) {
        try {
            DriverManager.getConnection(jdbcUrl, dbUser, dbPassword);
        } catch (SQLException e) {
            log.error("数据源配置 {} , 获取链接失败", jdbcUrl, e);
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 根据类型获取数据库驱动名称
     * @param type 数据库类型
     * @return
     * @author wuhao
     * @since 2.6.0 - 2022/7/21
     */
    private String convertDbDriverClassName(String type) {
        if("mysql".equals(type.toLowerCase())){
            return "com.mysql.cj.jdbc.Driver";
        }
        return null;
    }
}

